package com.lzyyj.common;

import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.proxy.Enhancer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class BeanWrapper {

	private static final Log log = LogFactory.getLog(BeanWrapper.class);
	
	private Map<Class<?>, Map<String, String>> relation;
		
	private BeanWrapper(Map<Class<?>, Map<String, String>> relation){
		this.relation = relation;
	}
	
	public static <T> T wrap(Class<T> clazz, String propertyList, Object source) {
		T wrapperBean = null;
		
		if (clazz!=null){
			
			Map<Class<?>, Map<String, String>> propertyRelation = parsePropertyRelation(clazz, propertyList, source==null?null:source.getClass());
			
			if (clazz.isInterface()){
				InvocationHandler invocationHandler = new ProxyWrapper<T>(propertyRelation.get(clazz), source);

				// 获得被代理类所实现的所有接口的数组，在这里数组中只有clazz.class一个元素
				Class<?>[] interfaces = new Class[]{clazz};

				// 获得类加载器
				ClassLoader loader = invocationHandler.getClass().getClassLoader();

				// 获得动态代理类的实例
				wrapperBean = (T)java.lang.reflect.Proxy.newProxyInstance(loader, interfaces, invocationHandler);
			}else{
				Enhancer en = new Enhancer();
				en.setSuperclass(clazz);
				en.setCallback(new CglibWrapper(propertyRelation.get(clazz), source));
				wrapperBean = (T) en.create();
			}
		}

		return wrapperBean ;
	}
	
	public <T> T wrap(Class<T> clazz, Object source) {
		T wrapperBean = null;
		
		if (clazz!=null){
						
			if (clazz.isInterface()){
				InvocationHandler invocationHandler = new ProxyWrapper<T>(relation.get(clazz), source);

				// 获得被代理类所实现的所有接口的数组，在这里数组中只有clazz.class一个元素
				Class<?>[] interfaces = new Class[]{clazz};

				// 获得类加载器
				ClassLoader loader = invocationHandler.getClass().getClassLoader();

				// 获得动态代理类的实例
				wrapperBean = (T)java.lang.reflect.Proxy.newProxyInstance(loader, interfaces, invocationHandler);
			}else{
				Enhancer en = new Enhancer();
				en.setSuperclass(clazz);
				en.setCallback(new CglibWrapper(relation.get(clazz), source));
				wrapperBean = (T) en.create();
			}
		}

		return wrapperBean ;
	}
	
	public static BeanWrapper getInstance(Class<?> targetClass, String propertyList, Class<?> sourceClass){
		BeanWrapper beanWrapper = null;
		
		Map<Class<?>, Map<String, String>> propertyRelation = parsePropertyRelation(targetClass, propertyList, sourceClass );
		beanWrapper = new BeanWrapper(propertyRelation);
		
		return beanWrapper;
	}
	
	private static Map<Class<?>, Map<String, String>> parsePropertyRelation(Class<?> tarClass, String propertyList, Class<?> sourceClass ){
		Map<Class<?>, Map<String, String>> relation = new HashMap<Class<?>, Map<String, String>>();
		Map<String, String> propertyMap = new HashMap<String, String>();
		Map<String, String> propertyMapB = new HashMap<String, String>();
		
		relation.put(sourceClass, propertyMap);
		relation.put(tarClass, propertyMapB);
		
		if(propertyList==null||propertyList.length()==0){
			// 未指定属性列表，默认为所有属性
			propertyList = BeanUtilsExt.getPropertyList(tarClass);
		}
		
		// 遍历属性列表，进行属性匹配
		Map<String, Object> sourcePropertyMap = BeanUtilsExt.getPropertyMap(sourceClass);
		Map<String, Object> targetPropertyMap = BeanUtilsExt.getPropertyMap(tarClass);
		String[] properties = propertyList.split(",");

		for(String property: properties){
			String relationName;
			String[] propertyRelation = property.split(":");
			// 是否有指定映射关系
			switch (propertyRelation.length) {
			case 1:
				property = propertyRelation[0];
				relationName = propertyRelation[0];
				matching(sourcePropertyMap, targetPropertyMap, property, relationName, propertyMap, propertyMapB);
				break;
			case 2:
				property = propertyRelation[0];
				relationName = propertyRelation[1];
				matching(sourcePropertyMap, targetPropertyMap, property, relationName, propertyMap, propertyMapB);
				break;
			default:
				break;
			}
		}
		return relation;
	}

	/**
	 * 对属性进行匹配操作
	 * @param sourcePropertyMap
	 * @param targetPropertyMap
	 * @param property
	 * @param relationName
	 */
	private static void matching(Map<String, Object> sourcePropertyMap, Map<String, Object> targetPropertyMap,
			String property, String relationName, Map<String, String> propertyRelation, Map<String, String> propertyMapB) {
		if (targetPropertyMap.containsKey(property)){
			// 这是一个属性
			if (sourcePropertyMap.containsKey(relationName)&&sourcePropertyMap.get(relationName)!=null&&sourcePropertyMap.get(relationName).equals(targetPropertyMap.get(property))){
				propertyRelation.put(property, relationName);
				propertyMapB.put(relationName, property);
				targetPropertyMap.remove(property);
				sourcePropertyMap.remove(relationName);
			}
		}else{
			// 这不是一个属性，估计是一个方法，先照搬吧
			propertyRelation.put(property, relationName);
			propertyMapB.put(relationName, property);
		}
	}

	public Map<Class<?>, Map<String, String>> getRelation() {
		return relation;
	}

	public void setRelation(Map<Class<?>, Map<String, String>> relation) {
		this.relation = relation;
	}
	
}
